/*
 * RegExEditorView.java
 */
package com.fkieviet;

import java.util.regex.Matcher;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.regex.Pattern;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
 * The application's main frame.
 */
public class RegExEditorView extends FrameView {

    private String generate() {
        StringBuilder ret = new StringBuilder();
        ret.append("// --- GLOBAL DECLARATION -- COPY AND PASTE\r\n");
        ret.append("public static Pattern REGEX = Pattern.compile(\"");
        ret.append(escapeJavaString(jRegex.getText()));
        ret.append("\", 0");

        if (jCanonical.isSelected()) {
            ret.append(" | Pattern.CANON_EQ");
        }
        if (jCaseInsensitive.isSelected()) {
            ret.append(" | Pattern.CASE_INSENSITIVE");
        }
        if (jComments.isSelected()) {
            ret.append(" | Pattern.COMMENTS");
        }
        if (jDotAll.isSelected()) {
            ret.append(" | Pattern.DOTALL");
        }
        if (jLiteral.isSelected()) {
            ret.append(" | Pattern.LITERAL");
        }
        if (jMultilLine.isSelected()) {
            ret.append(" | Pattern.MULTILINE");
        }
        if (jUnicode.isSelected()) {
            ret.append(" | Pattern.UNICODE_CASE");
        }
        if (jUnix.isSelected()) {
            ret.append(" | Pattern.UNIX_LINES");
        }
        ret.append(");\r\n");

        ret.append("\r\n\r\n// --- CODE -- COPY AND PASTE\r\n");
        ret.append("Matcher matcher = REGEX.matcher(input);\r\n");
        ret.append("if (!matcher.matches()) {\r\n");
        ret.append("  // no match\r\n");
        ret.append("} else {\r\n");
        ret.append("  if (matcher.groupCount() == 0) {\r\n");
        ret.append("    // no groups\r\n");
        ret.append("  } else {\r\n");
        ret.append("    for (int i = 0; i < matcher.groupCount(); i++) {\r\n");
        ret.append("      matcher.group(i + 1);\r\n");
        ret.append("    }\r\n");
        ret.append("  }\r\n");
        ret.append("}\r\n");

        return ret.toString();
    }

    private void regExChanged() {
        String[] lines;
        if (!jHasMultipleLines.isSelected()) {
            lines = new String[]{jToMatch.getText()};
        } else {
            String toMatchAll = jToMatch.getText();
            toMatchAll = toMatchAll.replace("\r\n", "\n");
            toMatchAll = toMatchAll.replace("\r", "\n");
            lines = toMatchAll.split("\n");
        }

        StringBuilder results = new StringBuilder();

        String regex = jRegex.getText();
        try {
            int options = 0;
            if (jCanonical.isSelected()) {
                options |= Pattern.CANON_EQ;
            }
            if (jCaseInsensitive.isSelected()) {
                options |= Pattern.CASE_INSENSITIVE;
            }
            if (jComments.isSelected()) {
                options |= Pattern.COMMENTS;
            }
            if (jDotAll.isSelected()) {
                options |= Pattern.DOTALL;
            }
            if (jLiteral.isSelected()) {
                options |= Pattern.LITERAL;
            }
            if (jMultilLine.isSelected()) {
                options |= Pattern.MULTILINE;
            }
            if (jUnicode.isSelected()) {
                options |= Pattern.UNICODE_CASE;
            }
            if (jUnix.isSelected()) {
                options |= Pattern.UNIX_LINES;
            }

            Pattern p = Pattern.compile(regex, options);
            for (String line : lines) {
                Matcher matcher = p.matcher(line);
                if (!matcher.matches()) {
                    results.append("<no match>\n");
                } else {
                    if (matcher.groupCount() == 0) {
                        results.append("<matches, no groups>\n");
                    } else {
                        results.append("<" + matcher.groupCount() + " groups> ");
                        for (int i = 0; i < matcher.groupCount(); i++) {
                            results.append(i + 1).append(":[").append(matcher.group(i + 1)).append("] ");
                        }
                        results.append("\n");
                    }
                }
            }
        } catch (Exception e) {
            results.append(e).append('\n');
        }
        jResults.setText(results.toString());
    }

    private String escapeJavaString(String inp) {
        StringBuilder ret = new StringBuilder();
        inp = inp.replace("\r\n", "\n");
        inp = inp.replace("\r", "\n");
        for (int i = 0; i < inp.length(); i++) {
            char c = inp.charAt(i);
            if (c == '\\') {
                ret.append('\\').append(c);
            } else if (c == '\"') {
                ret.append('\\').append(c);
            } else if (c == '\n') {
                ret.append("\\r\\n\" + \r\n  \"");
            } else if (c == '\t') {
                ret.append("\\t");
            } else {
                ret.append(c);
            }
        }

        return ret.toString();
    }

    private String unescapeJavaString(String inp) {
        StringBuilder ret = new StringBuilder();
        inp = inp.replace("\n", "");
        inp = inp.replace("\r", "");
        String[] lines = inp.split("\\\"\\s*\\+\\s*\\\"");
        for (String line : lines) {
            line = line.replace("\\\\", "\\");
            line = line.replace("\\\"", "\"");
            line = line.replace("\\r", "\r");
            line = line.replace("\\n", "\n");
            ret.append(line);
        }
        return ret.toString();
    }
    public static Pattern REVERSEJAVA = Pattern.compile("# Matches a string like \"public static Pattern REGEX = Pattern.compile(\"xxx\", 0 | Pattern.COMMENTS | Pattern.X);\r\n" +
            "\r\n" +
            "# Pre-amble -- something like \"public static Pattern P = \"\r\n" +
            ".*\r\n" +
            "\r\n" +
            "# Pattern.compile(\r\n" +
            "Pattern\\.compile\\(\r\n" +
            "\r\n" +
            "# Regex text\r\n" +
            "\\s*   \\\"(.*)\\\"  \\s*\r\n" +
            "\r\n" +
            "# Flags\r\n" +
            "(?:, \\s*   (.*)   \\s*  )?\r\n" +
            "\r\n" +
            "# Closing bracket\r\n" +
            "\\);\\s*", 0 | Pattern.COMMENTS | Pattern.DOTALL);

    private void reverseJava() {
        String toReverse = jRegex.getText();

        Matcher matcher = REVERSEJAVA.matcher(toReverse);
        if (!matcher.matches() || matcher.groupCount() < 1 || matcher.groupCount() > 2) {
            // no match
            JOptionPane.showMessageDialog(this.getComponent(),
                    "The text in the regular expression editor does not match a " +
                    "typical pattern declaration. " +
                    "A typical expression is \r\n" +
                    "   ... Pattern.compile(\"<regex>\");\r\n" +
                    "or\r\n" +
                    "   ... Pattern.compile(\"<regex>\", <options>);\r\n" +
                    "Fix the text in the regular expression editor (middle editor) and try again.\r\n\r\n" +
                    "For reference, the expression must match this pattern:\r\n" + REVERSEJAVA.pattern(),
                    "Java Pattern decoder", JOptionPane.ERROR_MESSAGE);
            
        } else {
            // Get regular expression
            String javapattern = matcher.group(1);
            String pattern = unescapeJavaString(javapattern);
            jRegex.setText(pattern);

            // Get flags
            if (matcher.groupCount() == 2) {
                String options = matcher.group(2);
                jCanonical.setSelected(options.indexOf("CANON_EQ") >= 0);
                jCaseInsensitive.setSelected(options.indexOf("CASE_INSENSITIVE") >= 0);
                jComments.setSelected(options.indexOf("COMMENTS") >= 0);
                jDotAll.setSelected(options.indexOf("DOTALL") >= 0);
                jLiteral.setSelected(options.indexOf("LITERAL") >= 0);
                jMultilLine.setSelected(options.indexOf("MULTILINE") >= 0);
                jUnicode.setSelected(options.indexOf("UNICODE_CASE") >= 0);
                jUnix.setSelected(options.indexOf("UNIX_LINES") >= 0);
            }

            regExChanged();
        }
    }

    public RegExEditorView(SingleFrameApplication app) {
        super(app);

        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String) (evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer) (evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
    }

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = RegExEditorApp.getApplication().getMainFrame();
            aboutBox = new RegExEditorAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        RegExEditorApp.getApplication().show(aboutBox);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        jSplitPane1 = new javax.swing.JSplitPane();
        jSplitPane2 = new javax.swing.JSplitPane();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jRegex = new javax.swing.JTextArea();
        jPanel3 = new javax.swing.JPanel();
        jEval = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        jGenerate = new javax.swing.JButton();
        jPanel5 = new javax.swing.JPanel();
        jCanonical = new javax.swing.JCheckBox();
        jCaseInsensitive = new javax.swing.JCheckBox();
        jComments = new javax.swing.JCheckBox();
        jDotAll = new javax.swing.JCheckBox();
        jLiteral = new javax.swing.JCheckBox();
        jMultilLine = new javax.swing.JCheckBox();
        jUnicode = new javax.swing.JCheckBox();
        jUnix = new javax.swing.JCheckBox();
        jPanel4 = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        jResults = new javax.swing.JTextArea();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        jToMatch = new javax.swing.JTextArea();
        jHasMultipleLines = new javax.swing.JCheckBox();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();

        mainPanel.setName("mainPanel"); // NOI18N
        mainPanel.setLayout(new java.awt.BorderLayout());

        jSplitPane1.setDividerLocation(150);
        jSplitPane1.setDividerSize(10);
        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane1.setName("jSplitPane1"); // NOI18N

        jSplitPane2.setDividerLocation(200);
        jSplitPane2.setDividerSize(10);
        jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane2.setLastDividerLocation(400);
        jSplitPane2.setName("jSplitPane2"); // NOI18N

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(com.fkieviet.RegExEditorApp.class).getContext().getResourceMap(RegExEditorView.class);
        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder(resourceMap.getString("jPanel2.border.title"))); // NOI18N
        jPanel2.setName("jPanel2"); // NOI18N
        jPanel2.setLayout(new java.awt.BorderLayout());

        jScrollPane1.setName("jScrollPane1"); // NOI18N

        jRegex.setColumns(20);
        jRegex.setRows(5);
        jRegex.setText(resourceMap.getString("jRegex.text")); // NOI18N
        jRegex.setName("jRegex"); // NOI18N
        jRegex.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                regExChanged(evt);
            }
        });
        jScrollPane1.setViewportView(jRegex);

        jPanel2.add(jScrollPane1, java.awt.BorderLayout.CENTER);

        jPanel3.setName("jPanel3"); // NOI18N
        jPanel3.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jEval.setText(resourceMap.getString("jEval.text")); // NOI18N
        jEval.setName("jEval"); // NOI18N
        jEval.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jEvalActionPerformed(evt);
            }
        });
        jPanel3.add(jEval);

        jButton2.setText(resourceMap.getString("jButton2.text")); // NOI18N
        jButton2.setName("jButton2"); // NOI18N
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });
        jPanel3.add(jButton2);

        jGenerate.setText(resourceMap.getString("jGenerate.text")); // NOI18N
        jGenerate.setName("jGenerate"); // NOI18N
        jGenerate.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jGenerateActionPerformed(evt);
            }
        });
        jPanel3.add(jGenerate);

        jPanel2.add(jPanel3, java.awt.BorderLayout.SOUTH);

        jPanel5.setName("jPanel5"); // NOI18N
        jPanel5.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 5, 0));

        jCanonical.setText(resourceMap.getString("jCanonical.text")); // NOI18N
        jCanonical.setName("jCanonical"); // NOI18N
        jPanel5.add(jCanonical);

        jCaseInsensitive.setText(resourceMap.getString("jCaseInsensitive.text")); // NOI18N
        jCaseInsensitive.setName("jCaseInsensitive"); // NOI18N
        jCaseInsensitive.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jCaseInsensitiveActionPerformed(evt);
            }
        });
        jPanel5.add(jCaseInsensitive);

        jComments.setSelected(true);
        jComments.setText(resourceMap.getString("jComments.text")); // NOI18N
        jComments.setName("jComments"); // NOI18N
        jComments.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jCommentsActionPerformed(evt);
            }
        });
        jPanel5.add(jComments);

        jDotAll.setText(resourceMap.getString("jDotAll.text")); // NOI18N
        jDotAll.setName("jDotAll"); // NOI18N
        jDotAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jDotAllActionPerformed(evt);
            }
        });
        jPanel5.add(jDotAll);

        jLiteral.setText(resourceMap.getString("jLiteral.text")); // NOI18N
        jLiteral.setName("jLiteral"); // NOI18N
        jLiteral.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jLiteralActionPerformed(evt);
            }
        });
        jPanel5.add(jLiteral);

        jMultilLine.setText(resourceMap.getString("jMultilLine.text")); // NOI18N
        jMultilLine.setName("jMultilLine"); // NOI18N
        jMultilLine.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMultilLineActionPerformed(evt);
            }
        });
        jPanel5.add(jMultilLine);

        jUnicode.setText(resourceMap.getString("jUnicode.text")); // NOI18N
        jUnicode.setName("jUnicode"); // NOI18N
        jUnicode.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jUnicodeActionPerformed(evt);
            }
        });
        jPanel5.add(jUnicode);

        jUnix.setText(resourceMap.getString("jUnix.text")); // NOI18N
        jUnix.setName("jUnix"); // NOI18N
        jUnix.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jUnixActionPerformed(evt);
            }
        });
        jPanel5.add(jUnix);

        jPanel2.add(jPanel5, java.awt.BorderLayout.NORTH);

        jSplitPane2.setLeftComponent(jPanel2);

        jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder(resourceMap.getString("jPanel4.border.title"))); // NOI18N
        jPanel4.setName("jPanel4"); // NOI18N
        jPanel4.setLayout(new java.awt.BorderLayout());

        jScrollPane2.setName("jScrollPane2"); // NOI18N

        jResults.setColumns(20);
        jResults.setRows(5);
        jResults.setText(resourceMap.getString("jResults.text")); // NOI18N
        jResults.setName("jResults"); // NOI18N
        jScrollPane2.setViewportView(jResults);

        jPanel4.add(jScrollPane2, java.awt.BorderLayout.CENTER);

        jSplitPane2.setRightComponent(jPanel4);

        jSplitPane1.setRightComponent(jSplitPane2);

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(resourceMap.getString("jPanel1.border.title"))); // NOI18N
        jPanel1.setName("jPanel1"); // NOI18N
        jPanel1.setLayout(new java.awt.BorderLayout());

        jScrollPane3.setName("jScrollPane3"); // NOI18N

        jToMatch.setColumns(20);
        jToMatch.setRows(5);
        jToMatch.setText(resourceMap.getString("jToMatch.text")); // NOI18N
        jToMatch.setName("jToMatch"); // NOI18N
        jToMatch.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jToMatchKeyReleased(evt);
            }
        });
        jScrollPane3.setViewportView(jToMatch);

        jPanel1.add(jScrollPane3, java.awt.BorderLayout.CENTER);

        jHasMultipleLines.setSelected(true);
        jHasMultipleLines.setText(resourceMap.getString("jHasMultipleLines.text")); // NOI18N
        jHasMultipleLines.setName("jHasMultipleLines"); // NOI18N
        jHasMultipleLines.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jHasMultipleLinesActionPerformed(evt);
            }
        });
        jPanel1.add(jHasMultipleLines, java.awt.BorderLayout.SOUTH);

        jSplitPane1.setLeftComponent(jPanel1);

        mainPanel.add(jSplitPane1, java.awt.BorderLayout.CENTER);

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(com.fkieviet.RegExEditorApp.class).getContext().getActionMap(RegExEditorView.class, this);
        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        org.jdesktop.layout.GroupLayout statusPanelLayout = new org.jdesktop.layout.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(statusPanelSeparator, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 658, Short.MAX_VALUE)
            .add(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(statusMessageLabel)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 484, Short.MAX_VALUE)
                .add(progressBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(statusPanelLayout.createSequentialGroup()
                .add(statusPanelSeparator, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(statusMessageLabel)
                    .add(statusAnimationLabel)
                    .add(progressBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .add(3, 3, 3))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

private void regExChanged(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_regExChanged
    regExChanged();
}//GEN-LAST:event_regExChanged

private void jHasMultipleLinesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jHasMultipleLinesActionPerformed
    jDotAll.setSelected(true);
    regExChanged(null);
}//GEN-LAST:event_jHasMultipleLinesActionPerformed

private void jEvalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jEvalActionPerformed
    regExChanged(null);
}//GEN-LAST:event_jEvalActionPerformed

private void jUnixActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jUnixActionPerformed
    regExChanged(null);
}//GEN-LAST:event_jUnixActionPerformed

private void jCaseInsensitiveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCaseInsensitiveActionPerformed
    regExChanged(null);
}//GEN-LAST:event_jCaseInsensitiveActionPerformed

private void jCommentsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCommentsActionPerformed
    regExChanged(null);
}//GEN-LAST:event_jCommentsActionPerformed

private void jDotAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jDotAllActionPerformed
    regExChanged(null);
}//GEN-LAST:event_jDotAllActionPerformed

private void jLiteralActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jLiteralActionPerformed
    regExChanged(null);
}//GEN-LAST:event_jLiteralActionPerformed

private void jMultilLineActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMultilLineActionPerformed
    regExChanged(null);
}//GEN-LAST:event_jMultilLineActionPerformed

private void jUnicodeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jUnicodeActionPerformed
    regExChanged(null);
}//GEN-LAST:event_jUnicodeActionPerformed

private void jGenerateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jGenerateActionPerformed
    jResults.setText(generate());
}//GEN-LAST:event_jGenerateActionPerformed

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
    reverseJava();
}//GEN-LAST:event_jButton2ActionPerformed

private void jToMatchKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jToMatchKeyReleased
    regExChanged(null);
}//GEN-LAST:event_jToMatchKeyReleased

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton2;
    private javax.swing.JCheckBox jCanonical;
    private javax.swing.JCheckBox jCaseInsensitive;
    private javax.swing.JCheckBox jComments;
    private javax.swing.JCheckBox jDotAll;
    private javax.swing.JButton jEval;
    private javax.swing.JButton jGenerate;
    private javax.swing.JCheckBox jHasMultipleLines;
    private javax.swing.JCheckBox jLiteral;
    private javax.swing.JCheckBox jMultilLine;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JTextArea jRegex;
    private javax.swing.JTextArea jResults;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JTextArea jToMatch;
    private javax.swing.JCheckBox jUnicode;
    private javax.swing.JCheckBox jUnix;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    // End of variables declaration//GEN-END:variables
    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;
}
